Haxe + CreateJS 開発メモ#5 removeEventListener が機能しない問題の回避方法
以前取り上げましたが、EaselJS v0.6.0 からイベントモデルが変更されています。
EventDispatcher クラスが実装されて、addEventListener や removeEventListener、dispatchEvent 等のメソッドが使えるようになりました。 しかし、Haxe で実装した場合、removeEventListener が正しく動かない場合があるようです。なかなか致命的です。
サンプル
package ; import createjs.easeljs.EventDispatcher; import haxe.Log; class RemoveEventListenerTest extends EventDispatcher { public function new() { addEventListener("test", testHandler); dispatchEvent("test"); dispatchEvent("test"); } private function testHandler(e:Dynamic):Void { removeEventListener(e.type, testHandler); Log.trace(e); } }
出力結果
RemoveEventListenerTest.hx:16: { type : test, target : [EventDispatcher] } Boot.hx:45 RemoveEventListenerTest.hx:16: { type : test, target : [EventDispatcher] } Boot.hx:45
上記の例では、最初にイベントが送出された時点で removeEventListener しているはずなのですが、ログが二度出力されてしまいます。
この問題を調査した所、addEventListener や removeEventListener に渡される関数がクラスの prototype にある場合に、Haxe コンパイラによってクロージャでラップされてしまう事が原因のようです。このため、EventDispatcher の持つリスナーオブジェクト内の関数との比較が一致せず、イベントリスナの除去が正しく行われません。
幸い、元の関数とコンテキストへの参照がアクセス可能なので、これらの値を利用して、Haxe でも正しく動作する removeEventListener メソッドを作ってみます。
(function() {
var p = createjs.EventDispatcher.prototype;
p.removeEventListener = function(type, listener) {
var listeners = this._listeners;
if (!listeners) { return; }
var arr = listeners[type];
if (!arr) { return; }
for (var i=0,l=arr.length; i
※2013/06/11追記
また、MouseEvent 等のクラスは、実際には EventDispatcher を直接継承していないので、個別にメソッドを上書きする必要があります。